﻿using System;
using System.Linq;
using System.Collections.ObjectModel;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media.Animation;
using System.Windows.Media.Imaging;
using System.Windows.Threading;
using SnakeGame.Models;
using SnakeGame.Views;
using SnakeGame.Helpers;


namespace SnakeGame.ViewModels
{
    class GamePageViewModel : NotifyPropertyChanged
    {
        public ICommand SelectionCommand { get; set; }
        public ICommand NewGameCommand { get; set; }
        private System.Timers.Timer _timer;
        private ObservableCollection<Player> _playerList;

        public ObservableCollection<Player> PlayerList
        {
            get { return _playerList; }
            set
            {
                _playerList = value;
                OnPropertyChanged("PlayerList");
            }
        }
        private MainFrame _mainFrame;

        private int _totalPlayer;
        private Random _rd = new Random();
        private const int MAX_ROW = 5;
        private const int MAX_COLUMN = 10;
        private const int MAX_CELL = 50;
        private int[,] points = new int[MAX_CELL, 2];             // checks Row and col of Data grid
        private Grid _gameGrid;
        private Dictionary<int, Question> _questions = new Dictionary<int, Question>();

        public string Toss { get; set; }

        public GamePageViewModel()
        {
            SelectionCommand = new RelayCommand(OnSelectionCommand);
            NewGameCommand = new RelayCommand(OnNewGameCommand);
        }

        private void OnNewGameCommand(object obj)
        {
            _mainFrame.NewGame();
        }

        private void OnSelectionCommand(object obj)
        {
            var player = obj as Player;
            if (player == null)
                return;
            
            player.Avatar.SetValue(Canvas.ZIndexProperty, 1);
            StepWindow step = new StepWindow();
            step.Owner = _mainFrame.Window;
            step.Initialize(player);
            step.ShowDialog();
            player.Avatar.SetValue(Canvas.ZIndexProperty, 0);

            //MessageBox.Show("Go" + " " + step.GoValue);

            if (!step.IsCancelled)
            {
                MovePlayer(true, player.Index, step.GoValue, false);
            }
        }

        private void ShowQuestion(int playerIndex)
        {
            int position = _playerList[playerIndex].Position;
            if (_questions.ContainsKey(position))
            {
                Question q = _questions[position];
                if (q == null)
                {
                    return;
                }

                MyMediaPlayer m = new MyMediaPlayer();
                m.Open(new Uri("question.mp3", UriKind.Relative));
                m.Play();

                QuestionWindow qWindow = new QuestionWindow();
                qWindow.Owner = _mainFrame.Window;
                qWindow.Initialize(_mainFrame, q, playerIndex);

                DoubleAnimation animFadeIn = new DoubleAnimation();
                animFadeIn.From = 0;
                animFadeIn.To = 1;
                animFadeIn.Duration = new Duration(TimeSpan.FromSeconds(1));
                qWindow.BeginAnimation(Window.OpacityProperty, animFadeIn);

                qWindow.ShowDialog();

                if (qWindow.IsWin)
                {
                    //MessageBox.Show("Win" + " " + q.Win);

                    if (q.Win == 999)
                    {
                        //redraw
                        SelectionCommand.Execute(_playerList[playerIndex]);
                        return;
                    }
                    _playerList[playerIndex].Win++;
                    MovePlayer(false, playerIndex, q.Win, q.Ladder);
                }
                else
                {
                    if (q.Win == 999)
                    {
                        //redraw
                        SelectionCommand.Execute(_playerList[playerIndex]);
                        return;
                    }
                    //MessageBox.Show("Lose" + " " + q.Lose);
                    _playerList[playerIndex].Lose++;
                    MovePlayer(false, playerIndex, q.Lose, q.Ladder);
                }
            }
        }

        private void UpdateDragon(int xPos, int yPos, Image avatar)
        {
            var xAnimation = new DoubleAnimation() { To = xPos, Duration = TimeSpan.FromSeconds(1) };
            var yAnimation = new DoubleAnimation() { To = yPos, Duration = TimeSpan.FromSeconds(1) };

            Storyboard.SetTarget(xAnimation, avatar);
            Storyboard.SetTargetProperty(xAnimation, new PropertyPath("(Image.RenderTransform).(TranslateTransform.X)"));

            Storyboard.SetTarget(yAnimation, avatar);
            Storyboard.SetTargetProperty(yAnimation, new PropertyPath("(Image.RenderTransform).(TranslateTransform.Y)"));

            var sb = new Storyboard();
            sb.Children.Add(xAnimation);
            sb.Children.Add(yAnimation);
            sb.Begin();

        }

        private void MovePlayer(bool showQuestion, int playerIndex, int step, bool ladder)
        {
            int currentPosition = PlayerList[playerIndex].Position;
            int moveToPosition = currentPosition + step;
            if (moveToPosition >= MAX_CELL)
            {
                moveToPosition = 49;
            }

            if (moveToPosition < 0)
            {
                //if (currentPosition - moveToPosition < 0) // out of bound
                    moveToPosition = 0;
            }

            _timer = new System.Timers.Timer(300);
            _timer.Enabled = true;
            _timer.Elapsed += (sender, e) => _timer_Elapsed(showQuestion, playerIndex, moveToPosition, ladder);
            _timer.Start();
        }

        private void _timer_Elapsed(bool showQuestion, int playerIndex, int step, bool ladder)
        {
            lock (this)
            {
                var i = PlayerList[playerIndex].Position;
                if (i == step)
                {
                    _timer.Stop();
                    if (step >= MAX_CELL - 1)
                    {
                        Application.Current.Dispatcher.Invoke(new ShowFinishDialogCallback(this.ShowFinishDialog),
                            new object[] { playerIndex });
                        return;
                    }

                    if (showQuestion)
                    {
                        Application.Current.Dispatcher.Invoke(new QuestionCallback(this.Question),
                            new object[] {playerIndex});
                    }

                    return;
                }

                if (!ladder)
                {
                    if (step > i)
                        i++;
                    else
                        i--;
                }
                else
                {
                    i = step;
                }

                Application.Current.Dispatcher.Invoke(new MovementCallback(this.Movement),
                    new object[] { PlayerList[playerIndex].Avatar, playerIndex, i }
                );
            }
        }


        public delegate void MovementCallback(Image av, int index, int i);
        public void Movement(Image av, int playerIndex, int i)
        {
            //DoubleAnimation animFadeIn = new DoubleAnimation();
            //animFadeIn.From = 0.5;
            //animFadeIn.To = 1;
            //animFadeIn.Duration = new Duration(TimeSpan.FromSeconds(0.3));
            //PlayerList[playerIndex].Avatar.BeginAnimation(Window.OpacityProperty, animFadeIn);

            _gameGrid.Children.Remove(av);
            PlayerList[playerIndex].Avatar.SetValue(Grid.RowProperty, points[i, 0]);
            PlayerList[playerIndex].Avatar.SetValue(Grid.ColumnProperty, points[i, 1]);
            PlayerList[playerIndex].Position = i;
            _gameGrid.Children.Add(av);

            MyMediaPlayer MediaPlayer = new MyMediaPlayer();
            MediaPlayer.Open(new Uri("step.wav", UriKind.Relative));
            MediaPlayer.Play();


        }
        public delegate void QuestionCallback(int playerIndex);
        public void Question(int playerIndex)
        {
            ShowQuestion(playerIndex);
        }

        public delegate void ShowFinishDialogCallback(int playerIndex);
        public void ShowFinishDialog(int playerIndex)
        {
            //MessageBox.Show("END GAME");
            WinnerWindow w = new WinnerWindow();
            w.Owner = _mainFrame.Window;
            w.Initialize(_mainFrame, PlayerList[playerIndex]);

            DoubleAnimation anime = new DoubleAnimation();
            anime.From = 0;
            anime.To = 1;
            anime.Duration = new Duration(TimeSpan.FromSeconds(1));
            w.BeginAnimation(Window.OpacityProperty, anime);

            w.ShowDialog();
        }

        internal void Initialize(Views.MainFrame mainFrame, Grid gameGrid)
        {
            _mainFrame = mainFrame;
            _gameGrid = gameGrid;
            // Player
            PlayerList = mainFrame.Players;

            _totalPlayer = PlayerList.Count;
            int i = 1;
            foreach (var item in PlayerList.Reverse())
            {
                Image im = new Image();
                if (String.IsNullOrEmpty(item.CharacterPicture))
                {
                    item.CharacterPicture = @"pack://application:,,,/Resources/" + i.ToString() + ".png";
                }
                im.Source = new BitmapImage(new Uri(item.CharacterPicture));
                im.SetValue(Grid.RowProperty, 0);
                im.SetValue(Grid.ColumnProperty, 9);

                _gameGrid.Children.Add(im);
                item.Avatar = im;
                ++i;
            }

            //Board
            bool isOddRow = true;
            int index = 0;
            for (int row = 0; row < MAX_ROW; ++row)
            {
                if (isOddRow)
                {
                    for (int column = MAX_COLUMN-1; column >= 0; --column, ++index)
                    {
                        points[index, 0] = row;
                        points[index, 1] = column;
                    }
                }
                else
                {
                    for (int column = 0; column < MAX_COLUMN; ++column, ++index)
                    {
                        points[index, 0] = row;
                        points[index, 1] = column;
                    }    
                }
                isOddRow = !isOddRow;
            }

            #region Test Write JSON
            //Dictionary<int, Question> myQuestions = new Dictionary<int, Question>();

            //Question a = new Question
            //{
            //    Quest = "Who are you?",
            //    Win = 2,
            //    Lose = -2,
            //    Timeout = 7 * 60 * 60
            //};

            //for (int i = 1; i <= 30; ++i)
            //{
            //    myQuestions.Add(i, a);
            //}

            //string json = JsonConvert.SerializeObject(myQuestions, Formatting.Indented);
            //File.WriteAllText(@"c:\config.json", json);
            #endregion


            try
            {
                var myList = ConfigManager.ReadConfigFromFile();
                _questions = myList.Where(g => g.IsUsed == true).ToDictionary(g => g.ID, g => g);
                
            }
            catch
            {
                MessageBox.Show("Unable to read setting from Config file");
            }
        }
    }
}
